package com.magic.manager.impl;

import com.magic.enums.MeetingEventEnum;
import com.magic.manager.IMeetingEventManager;
import com.magic.process.IMeetingEvent;
import com.magic.process.IMeetingOperator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author magic
 * @version 1.0
 * @date 2022/2/22 14:47
 */
@Slf4j
@Component
public class MeetingEventManager implements IMeetingEventManager, ApplicationContextAware {
  /**
   * 用于保存接口实现类名及对应的类
   */
  private Map<String, IMeetingOperator> map = new ConcurrentHashMap<>(16);


  @Override
  public List<IMeetingOperator> load(MeetingEventEnum eventEnum) {
    if (map != null && eventEnum != null) {
      try {
        return map.values().stream().filter(t -> t.support(eventEnum)).collect(Collectors.toList());
      } catch (Exception e) {
        log.error("load event = {} operator error, {}", e, eventEnum.getClass().getName());
      }
    }
    log.warn("load event operator empty!");
    return null;
  }

  /**
   * 获取应用上下文并获取相应的接口实现类
   * @param applicationContext
   * @throws BeansException
   */
  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    map = applicationContext.getBeansOfType(IMeetingOperator.class);
    //根据接口类型返回相应的所有bean
    Map<String, IMeetingEvent> eventMap = applicationContext.getBeansOfType(IMeetingEvent.class);
    for (Map.Entry<String, IMeetingEvent> eventEntry : eventMap.entrySet()) {
      try {
        IMeetingEvent meetingEvent = eventEntry.getValue();
        Class clazz = meetingEvent.getClass();
        Set<Class> interfaces = new HashSet<>();
        interfaces = getIMeetingEventSubInterfaces(interfaces, clazz);
        //getActualTypeArguments获取参数化类型的数组，泛型可能有多个
        Set<IMeetingOperator> operatorSet = new HashSet();
        for (Class i : interfaces) {
          MeetingEventEnum event = MeetingEventEnum.get(i);
          if (event != null) {
            operatorSet.addAll(load(event));
          } else {
            log.warn("bind Event operator error event interface = {}", i);
          }
        }
        //operator按照约定order执行
        List<IMeetingOperator> operators =
                operatorSet.stream().sorted(Comparator.comparingInt(o -> o.currentOrder().getValue()))
                        .collect(Collectors.toList());
        meetingEvent.bindEventOperator(operators);
        log.debug("event {} load operator {}", meetingEvent, operators);
      } catch (Exception e) {
        log.error("bind Event operator error", e);
      }
    }
  }



  /**
   * 获取当前实现类的所有 IMeetingEvent 的子接口
   * @param subInterfaces
   * @param clazz
   * @return
   */
  private Set<Class> getIMeetingEventSubInterfaces(Set<Class> subInterfaces, Class clazz) {
    Class[] interfaces = clazz.getInterfaces();
    if (interfaces == null || interfaces.length == 0) {
      log.debug("check event [{}]未实现任何接口", clazz);
      return subInterfaces;
    }
    for(Class c : interfaces) {
      Class[] superInterfaces = c.getInterfaces();
      if(superInterfaces == null || superInterfaces.length == 0) {
        log.debug("check event [{}]的接口[{}]未继承任何接口", clazz, c);
        continue;
      }
      for(Class superInterface : superInterfaces) {
        if(superInterface == IMeetingEvent.class) {
          log.info("check event [{}]的接口[{}]继承了IMeetingEvent接口", clazz, c);
          subInterfaces.add(c);
        } else {
          log.debug("check event [{}]的接口[{}]未继承IMeetingEvent接口", clazz, c);
          continue;
        }
      }
    }
    Class superClass = clazz.getSuperclass();
    if(Objects.nonNull(superClass) && superClass != Object.class) {
      subInterfaces.addAll(getIMeetingEventSubInterfaces(subInterfaces, superClass));
    }
    return subInterfaces;
  }
}
